﻿#include "ff.h"
#include "lrc_api.h"
#include "lrc_util.h"
#include "db_format.h"

#ifdef WIN32
#include <stdio.h> 
#include "assert.h"
#define MALLOC malloc
#define FREE free
#else
#include "sys_types.h"
// extern int sscanf(char *buf, const char *format, ...);
#define MALLOC OAL_malloc
#define FREE OAL_free
#define assert(...)
#endif


typedef struct tagLrcNode
{
    unsigned short sec;
    unsigned short offset;
}LRCNODE;

typedef struct tagLrcContent
{
	FIL* f_txt;
	int default_format;//default_format：ANSI_FORMAT==国标码优先；others==utf8优先
	int format;

	LRCNODE* lrc_list;
	int lrc_cnt;

	unsigned char lrcdata[LRC_MAX_BYTES];
}LRC_CONTENT;

LRC_CONTENT * hlrc;

int lrc_init_(char * fname);
int lrc_get_(unsigned short offset);

int lrc_init(char * fname, int default_format)//default_format：ANSI_FORMAT==国标码优先；others==utf8优先
{
	lrc_free();

	hlrc = (LRC_CONTENT*)MALLOC(sizeof(LRC_CONTENT));
	memset(hlrc, 0, sizeof(LRC_CONTENT));

	hlrc->default_format = default_format;

	if(0 != lrc_init_(fname))
	{
		lrc_free();
		return -1;
	}

	return 0;
}

void lrc_free(void)
{
	if(hlrc)
	{
		if(hlrc->lrc_list)
		{
			FREE(hlrc->lrc_list);
			hlrc->lrc_list = 0;
			hlrc->lrc_cnt = 0;
		}
		lrc_ffclose(&hlrc->f_txt);
		FREE(hlrc);
		hlrc = 0;
	}
}

int lrc_get(unsigned short ts, unsigned char ** txt)
{
	int i;

	*txt = 0;

	if(hlrc->lrc_cnt == 0)
	{
		return -1;
	}

	if(ts > hlrc->lrc_list[hlrc->lrc_cnt-1].sec)
	{
		return -1; //over
	}

	for(i=0; i<hlrc->lrc_cnt; i++)
	{
		if(ts == hlrc->lrc_list[i].sec)
		{
			if(0==lrc_get_(hlrc->lrc_list[i].offset))
			{
				*txt = hlrc->lrcdata;
				return 1;//has lrc at this time, render it
			}
			else
			{
				return -2;//fs error
			}
		}
	}

	return 0; //no lrc at this time
}

int lrc_count(void)
{
	unsigned int i;
	int res = 0;
	int offset = 0;
	char* buff = (char*)MALLOC(1024);
	if(buff == 0)	return -1;

	switch(hlrc->format)
	{
	case ASCII_FORMAT			:
	case ANSI_FORMAT			:
	case UTF_8_NOBOM_FORMAT		:
		offset = 0;
		break;

	case UTF_8_BOM_FORMAT		:
	case UTF_16_L_ENDIAN_FORMAT	:
	case UTF_16_B_ENDIAN_FORMAT	:
		offset = 3;
		break;

	case UTF_32_L_ENDIAN_FORMAT	:
	case UTF_32_B_ENDIAN_FORMAT	:
	case ERROR_FORMAT			:
		assert(0);
		break;

	default						:
		assert(0);
		break;
	}

	res += f_lseek(hlrc->f_txt, offset);
	if(res){
		FREE(buff);
		return res;
	}


	hlrc->lrc_cnt = 0;
	for(;;)
	{
		if(0 == f_gets(buff, 1024, hlrc->f_txt))	break;

		if(buff[0] == '[' && buff[1] >= '0' && buff[1] <= '9')
		{
			hlrc->lrc_cnt++;
			for(i=0;i<strlen(buff);i++)
			{
				if(i+2 < strlen(buff))
				if(buff[i]==']' && buff[i+1]=='[' && buff[i+2] >= '0' && buff[i+2] <= '9')
				{
					hlrc->lrc_cnt++;
				}
			}
		}
    }

	FREE(buff);
	return 0;
}

unsigned short get_sec(char * buff)
{
	int m = 0;
	int s = 0;
	m = (buff[1]-'0');
	m = m*10 + (buff[2]-'0');

	s = (buff[4]-'0');
	s = s*10 + (buff[5]-'0');
	return (unsigned short)(m*60+s);

	//int ret = sscanf(buff, "[%d:%f]", &m, &s);
	//assert(ret == 2);
	//sscanf(buff, "[%d:%f]", &m, &s);
	//return (unsigned short)(m*60+(int)(s+0.5));
}

int lrc_paser(void)
{
	int i, j;
	FSIZE_t offset = 0;
	int res = 0;
	char* buff = (char*)MALLOC(1024);
	if(buff == 0)	return -1;

	switch(hlrc->format)
	{
	case ASCII_FORMAT			:
	case ANSI_FORMAT			:
	case UTF_8_NOBOM_FORMAT		:
		offset = 0;
		break;

	case UTF_8_BOM_FORMAT		:
	case UTF_16_L_ENDIAN_FORMAT	:
	case UTF_16_B_ENDIAN_FORMAT	:
		offset = 3;
		break;

	case UTF_32_L_ENDIAN_FORMAT	:
	case UTF_32_B_ENDIAN_FORMAT	:
	case ERROR_FORMAT			:
		assert(0);
		break;

	default						:
		assert(0);
		break;
	}

	res += f_lseek(hlrc->f_txt, offset);
	if(res){
		FREE(buff);
		return res;
	}

	for(j=0; j<hlrc->lrc_cnt;)
	{
		offset = f_tell(hlrc->f_txt);
		if(0 == f_gets(buff, 1024, hlrc->f_txt))	break;

		if(buff[0] == '[' && buff[1] >= '0' && buff[1] <= '9')
		{
			assert(j<hlrc->lrc_cnt);
			if(j<hlrc->lrc_cnt)
			{
				hlrc->lrc_list[j].offset = (unsigned short)offset;
				hlrc->lrc_list[j].sec = get_sec(&buff[0]);
				j++;
			}
			for(i=0; i<(int)strlen(buff); i++)
			{
				if(i+2 < (int)strlen(buff))
				if(buff[i]==']' && buff[i+1]=='[' && buff[i+2] >= '0' && buff[i+2] <= '9')
				{
					assert(j<hlrc->lrc_cnt);
					if(j<hlrc->lrc_cnt)
					{
						hlrc->lrc_list[j].offset = (unsigned short)offset;
						hlrc->lrc_list[j].sec = get_sec(&buff[i+1]);
						j++;
					}
				}
			}
		}
    }

	assert(j == hlrc->lrc_cnt);

	FREE(buff);
	return 0;
}

void lrc_sort(void)
{
	int i,j;

	for(i=0; i<hlrc->lrc_cnt-1; i++)
	{
		for(j=i+1; j<hlrc->lrc_cnt; j++)
		{
			if(hlrc->lrc_list[i].sec > hlrc->lrc_list[j].sec)
			{
				unsigned short tmp;
				tmp = hlrc->lrc_list[i].sec;
				hlrc->lrc_list[i].sec = hlrc->lrc_list[j].sec;
				hlrc->lrc_list[j].sec = tmp;
				tmp = hlrc->lrc_list[i].offset;
				hlrc->lrc_list[i].offset = hlrc->lrc_list[j].offset;
				hlrc->lrc_list[j].offset = tmp;
			}
		}
	}
}

int lrc_get_(unsigned short offset)
{
	unsigned int i, j;
	int res = 0;
	char* buff = (char*)MALLOC(1024);
	if(buff == 0)	return -1;

	res += f_lseek(hlrc->f_txt, offset);
	if(res)	return res;

	if(0==f_gets(buff, 1024, hlrc->f_txt))
	{
		FREE(buff);
		return res;
	}

	for(i=0, j=0; i<strlen(buff);)
	{
		//find data
		for(;i<strlen(buff);i++)
		{
			if(buff[i]==']')
			{
				++i;
				break;
			}
		}

		//move data
		for(;i<strlen(buff);i++,j++)
		{
			if(buff[i]=='[')
				break;
			buff[j] = buff[i];
		}
	}

	buff[j] = 0;

	lrc_str_to_utf8((unsigned char*)buff, hlrc->lrcdata, LRC_MAX_BYTES, hlrc->format);

	FREE(buff);
	return 0;
}

int get_format()
{
	int res = 0;
	unsigned int br;
	char* buff = (char*)MALLOC(1024);
	if(buff == 0) return 1;

	hlrc->format = ERROR_FORMAT;
	
	res += f_lseek(hlrc->f_txt, 0);
	if(res){
		FREE(buff);
		return res;
	}

	res = f_read(hlrc->f_txt,buff, 1024, &br);
	if(res == FR_OK)
	{
		hlrc->format = db_check_format((uint8_t*)buff, br, hlrc->default_format);
	}

	FREE(buff);
	return res;
}

int lrc_init_(char * fname)
{
	int res = 0;
	res += lrc_ffopen(&hlrc->f_txt, fname, FA_READ);
	if(res)	return res;

	res += get_format();
	if(res)	return res;
	res += lrc_count();
	if(res)	return res;

	if(hlrc->lrc_cnt == 0)
		return -1;

	hlrc->lrc_list = (LRCNODE*)MALLOC(hlrc->lrc_cnt * sizeof(LRCNODE));
	if(hlrc->lrc_list == 0)
		return -1;

	res += lrc_paser();
	if(res)	return res;

	lrc_sort();

	return 0;
}
